Skip to content

Fix unbound prefix recovery when xmlns:dlna is absent#53

Open
sfortis wants to merge 2 commits into
StevenLooman:masterfrom
sfortis:fix/unbound-prefix-without-dlna-namespace
Open

Fix unbound prefix recovery when xmlns:dlna is absent#53
sfortis wants to merge 2 commits into
StevenLooman:masterfrom
sfortis:fix/unbound-prefix-without-dlna-namespace

Conversation

@sfortis

@sfortis sfortis commented Jun 21, 2026

Copy link
Copy Markdown

Summary

The `strict=False` recovery added in #35 anchored its namespace injection on an existing `xmlns:dlna` declaration. Some real-world devices (JBL Authentics, WiiM/LinkPlay) emit `song:*` tags without declaring `xmlns:dlna`, so the injection was silently skipped and the unbound prefix remained, raising `ParseError` when the path was otherwise supposed to recover.

Observable today: `python-didl-lite==1.5.0` is shipped via `async-upnp-client` into Music Assistant, where JBL Authentics 200 owners still see ~100 `unbound prefix` errors per hour and a broken DLNA state-sync loop (downstream tracking: music-assistant/support#4398).

Fix

Anchor the namespace injection on the DIDL-Lite root opening tag (`<DIDL-Lite`) instead of the optional `xmlns:dlna` declaration. The root element is guaranteed to be present in any valid DIDL-Lite document, so recovery works regardless of which namespace declarations the producer chose to include.

Also batches all missing prefix injections into a single regex substitution rather than looping per-prefix.

Test

Added `test_from_xml_string_unbound_prefix_without_dlna_namespace` that exercises the no-`xmlns:dlna` case. The existing `test_from_xml_string_unbound_prefix` (with `xmlns:dlna` present) still passes.

```
$ python3 -m pytest tests/ -v
...
26 passed in 0.18s
```

`ruff check` clean.

Compatibility

  • No behavior change when `strict=True` (recovery gated by `if not strict`).
  • No behavior change for XML that did contain `xmlns:dlna` and had unbound prefixes (Handle unbound XML prefixes when strict=False #35 case continues to work).
  • Recovers an additional class of input that previously raised.

(Replaces #52, which was accidentally opened from the wrong account.)

sfortis and others added 2 commits June 21, 2026 13:37
The strict=False recovery added in StevenLooman#35 anchored its namespace injection
on an existing `xmlns:dlna` declaration. Some real-world devices (JBL
Authentics, WiiM/LinkPlay) emit `<song:*>` tags without declaring
`xmlns:dlna`, so the injection was silently skipped and the unbound
prefix remained, raising ParseError when otherwise recoverable.

Anchor the injection on the DIDL-Lite root opening tag instead. That
element is guaranteed to be present in any valid DIDL-Lite document, so
the recovery works regardless of which namespace declarations the
producer chose to include.

Also batch all missing prefixes into a single regex substitution and add
a regression test that exercises the no-dlna-namespace case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant